package com.canaan.business.service.storehouse.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.canaan.business.common.enums.basic.YNEnum;
import com.canaan.business.common.enums.inOutStock.InStockOrderTypeEnum;
import com.canaan.business.common.enums.inOutStock.OutStockOrderTypeEnum;
import com.canaan.business.common.enums.storehouse.CheckStatusEnum;
import com.canaan.business.common.enums.storehouse.CheckWayEnum;
import com.canaan.business.common.enums.storehouse.StorehouseStockStatusEnum;
import com.canaan.business.domain.basic.WmsStorehouse;
import com.canaan.business.domain.storehouse.*;
import com.canaan.business.domain.vo.*;
import com.canaan.business.mapper.storehouse.StockCheckMapper;
import com.canaan.business.service.basic.IWmsStorehouseService;
import com.canaan.business.service.inOutStock.IStockOccupyDetailService;
import com.canaan.business.service.inOutStock.IWmsInStockOrderService;
import com.canaan.business.service.inOutStock.IWmsOutStockOrderService;
import com.canaan.business.service.inOutStock.IWmsStockOccupyService;
import com.canaan.business.service.storehouse.*;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 库存盘点任务Service业务层处理
 *
 * @author ruoyi
 * @date 2023-02-14
 */
@Service
public class StockCheckServiceImpl implements IStockCheckService {
    @Resource
    private StockCheckMapper stockCheckMapper;
    @Resource
    private IStockCheckDetailService stockCheckDetailService;
    @Resource
    private IStockCheckPlanDetailService stockCheckPlanDetailService;
    @Resource
    private IWmsStorehouseStockService storehouseStockService;
    @Resource
    private IWmsStockOccupyService stockOccupyService;
    @Resource
    private IStockOccupyDetailService stockOccupyDetailService;

    @Resource
    private IStockCheckResultService stockCheckResultService;
    @Resource
    private IStockCheckDiffService stockCheckDiffService;
    @Resource
    private IWmsInStockOrderService wmsInStockOrderService;
    @Resource
    private IWmsOutStockOrderService wmsOutStockOrderService;
    @Resource
    private IWmsInOutStorageService wmsInOutStorageService;
    @Resource
    private IWmsStorehouseService storehouseService;

    @Resource
    private IStockCheckService stockCheckService;
    /**
     * 查询库存盘点任务
     *
     * @param id 库存盘点任务主键
     * @return 库存盘点任务
     */
    @Override
    public StockCheck selectStockCheckById(Long id) {
        return stockCheckMapper.selectStockCheckById(id);
    }

    /**
     * 查询库存盘点任务列表
     *
     * @param stockCheck 库存盘点任务
     * @return 库存盘点任务
     */
    @Override
    public List<StockCheck> selectStockCheckList(StockCheck stockCheck) {
        return stockCheckMapper.selectStockCheckList(stockCheck);
    }

    /**
     * 新增库存盘点任务
     *
     * @param stockCheck 库存盘点任务
     * @return 结果
     */
    @Override
    public int insertStockCheck(StockCheck stockCheck) {
        if(StringUtils.isBlank(stockCheck.getNo())){
            stockCheck.setNo(TableNoUtil.getNo(StockCheckResult.class));
        }
        stockCheck.setCreateBy(SecurityUtils.getUsername());
        stockCheck.setCreateTime(DateUtils.getNowDate());
        return stockCheckMapper.insertStockCheck(stockCheck);
    }

    /**
     * 批量新增库存盘点任务
     *
     * @param stockCheckList 库存盘点任务列表
     * @return 结果
     */
    @Override
    public int batchInsertStockCheck(List<StockCheck> stockCheckList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (StockCheck stockCheck : stockCheckList){
            if(StringUtils.isBlank(stockCheck.getNo())){
                stockCheck.setNo(TableNoUtil.getNo(StockCheck.class));
            }
            stockCheck.setCreateBy(username);
            stockCheck.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i=0; i<stockCheckList.size();) {
            int endIndex = i+500;
            if (endIndex > stockCheckList.size()) {
                endIndex = stockCheckList.size();
            }
            insertNum = insertNum + stockCheckMapper.batchInsertStockCheck(stockCheckList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改库存盘点任务
     *
     * @param stockCheck 库存盘点任务
     * @return 结果
     */
    @Override
    public int updateStockCheck(StockCheck stockCheck) {
        stockCheck.setUpdateBy(SecurityUtils.getUsername());
        stockCheck.setUpdateTime(DateUtils.getNowDate());
        return stockCheckMapper.updateStockCheck(stockCheck);
    }

    /**
     * 批量修改库存盘点任务
     *
     * @param stockCheckList 库存盘点任务列表
     * @return 结果
     */
    @Override
    public int batchUpdateStockCheck(List<StockCheck> stockCheckList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (StockCheck stockCheck : stockCheckList){
            stockCheck.setUpdateBy(username);
            stockCheck.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i=0; i<stockCheckList.size();) {
            int endIndex = i+500;
            if (endIndex > stockCheckList.size()) {
                endIndex = stockCheckList.size();
            }
            updateNum = updateNum + stockCheckMapper.batchUpdateStockCheck(stockCheckList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除库存盘点任务
     *
     * @param ids 需要删除的库存盘点任务主键集合
     * @return 结果
     */
    @Override
    public int deleteStockCheckByIds(Long[] ids) {
        StockCheck stockCheck = new StockCheck();
        stockCheck.setIds(CollUtil.toList(ids));
        List<StockCheck> stockChecks = selectStockCheckList(stockCheck);
        for (StockCheck check : stockChecks) {
            if (!(CheckStatusEnum.CREATE.getCode().equals(check.getStatus()))){
                throw new ServiceException("盘点任务状态是"+CheckStatusEnum.CREATE.getMessage()+"才可以删除");
            }else{
                //解锁库存
                stockOccupyService.unLock(check);
            }
            //去除锁定
            stockOccupyService.unLock(check);
        }
        return stockCheckMapper.deleteStockCheckByIds(ids);
    }

    /**
     * 删除库存盘点任务信息
     *
     * @param id 库存盘点任务主键
     * @return 结果
     */
    @Override
    public int deleteStockCheckById(Long id) {
        return stockCheckMapper.deleteStockCheckById(id);
    }

    /**
     * 查询库存盘点任务
     *
     * @param no 编号
     * @return 库存盘点任务
     */
    @Override
    public StockCheck selectStockCheckByNo(String no) {
        return stockCheckMapper.selectStockCheckByNo(no);
    }

    /**
     * 批量删除库存盘点任务
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deleteStockCheckByNos(String[] nos) {
        return stockCheckMapper.deleteStockCheckByNos(nos);
    }

    /**
     * 删除库存盘点任务信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deleteStockCheckByNo(String no) {
        return stockCheckMapper.deleteStockCheckByNo(no);
    }


    /**
     * 生成盘点任务
     * @author 梁建设
     * @since 2023/2/14 下午4:35
     */
    @Override
    public StockCheck generatorByPlan(StockCheckPlan stockCheckPlan) {
        StockCheck stockCheck = new StockCheck();
        stockCheck.setPlanNo(stockCheckPlan.getNo());
        stockCheck.setPlanName(stockCheckPlan.getName());
        stockCheck.setCheckType(stockCheckPlan.getCheckType());
        stockCheck.setCheckWay(stockCheckPlan.getCheckWay());
        stockCheck.setStatus(CheckStatusEnum.CREATE.getCode());
        stockCheck.setIsRepeatCheck(YNEnum.N.getCode());
        stockCheck.setStorehouseNo(stockCheckPlan.getStorehouseNo());
        WmsStorehouse wmsStorehouse = storehouseService.selectWmsStorehouseByNo(stockCheckPlan.getStorehouseNo());
        if (wmsStorehouse != null) {
            stockCheck.setStorehouseName(wmsStorehouse.getName());
        }
        stockCheck.setStorehouseName(stockCheckPlan.getStorehouseNo());
        this.insertStockCheck(stockCheck);
        List<StockCheckPlanDetail> stockCheckPlanDetails =
                stockCheckPlanDetailService.selectStockCheckPlanDetailByPlanNo(stockCheck.getPlanNo());
        List<StockCheckDetail> stockCheckDetails = new ArrayList<>();
        for (StockCheckPlanDetail stockCheckPlanDetail : stockCheckPlanDetails) {
            StockCheckDetail stockCheckDetail = new StockCheckDetail();
            stockCheckDetail.setCheckNo(stockCheck.getNo());
            stockCheckDetail.setProductNo(stockCheckPlanDetail.getProductNo());
            stockCheckDetail.setProductName(stockCheckPlanDetail.getProductName());
            stockCheckDetail.setStorehouseNo(stockCheckPlanDetail.getStorehouseNo());
            stockCheckDetail.setAreaNo(stockCheckPlanDetail.getAreaNo());
            stockCheckDetail.setLocationNo(stockCheckPlanDetail.getLocationNo());
            stockCheckDetails.add(stockCheckDetail);
        }
        stockCheckDetailService.batchInsertStockCheckDetail(stockCheckDetails);
        return stockCheck;
    }

    /**
     * 锁定库存
     * @author 梁建设
     * @since 2023/2/14 下午4:38
     * 锁定库存：判断如果判断方式是物料，则By仓库+物料锁定库存，如果是位置则By仓库+库位锁定库存（库存状态为正常，才能将库存状态更新为锁定）
     * 最后将锁定的库存数据插入到库存占用表，类型为盘库锁定
     * 是否复盘，如果不需要复盘盘点详情填入空集合，如果需要复盘需要填入复盘任务的明细
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkLock(StockCheck stockCheck,List<StockCheckDetail> stockCheckDetails) {
        List<WmsStorehouseStock> storehouseStockList = new ArrayList<>();
        if (CollectionUtil.isEmpty(stockCheckDetails)){
            stockCheckDetails = stockCheckDetailService.selectStockCheckDetailByCheckNo(stockCheck.getNo())  ;
        }
        List<WmsStorehouseStock> wmsStorehouseStockList = new ArrayList<>();
        for (StockCheckDetail stockCheckDetail : stockCheckDetails) {
            List<WmsStorehouseStock> wmsStorehouseStocks = new ArrayList<>();
            if (StrUtil.isNotBlank(stockCheckDetail.getProductNo())) {
                WmsStorehouseStock storehouseStock = new WmsStorehouseStock();
                storehouseStock.setProductNo(stockCheckDetail.getProductNo());
                storehouseStock.setStorehouseNo(stockCheck.getStorehouseNo());
                wmsStorehouseStocks = storehouseStockService.selectWmsStorehouseStockList(storehouseStock);
            } else if (StrUtil.isNotBlank(stockCheckDetail.getLocationNo())) {
                wmsStorehouseStocks = storehouseStockService.selectWmsStorehouseStockListByLocationNo(stockCheckDetail.getLocationNo());
            }
            long count = wmsStorehouseStocks.stream().filter(e -> StorehouseStockStatusEnum.LOCK.getCode().equals(e.getStatus())).count();
            if (count > 0) {
                throw new ServiceException("任务生成失败，请重新选择盘点范围");
            }
            wmsStorehouseStocks = wmsStorehouseStocks.stream().filter(e -> StorehouseStockStatusEnum.NORMAL.getCode().equals(e.getStatus())).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(wmsStorehouseStocks)) {
                storehouseStockList.addAll(wmsStorehouseStocks);
                wmsStorehouseStocks.stream().forEach(e -> e.setStatus(StorehouseStockStatusEnum.LOCK.getCode()));
                wmsStorehouseStockList.addAll(wmsStorehouseStocks);
                storehouseStockService.batchUpdateWmsStorehouseStock(wmsStorehouseStocks);
            }
        }
        //添加库存占用信息
        stockOccupyService.createLock(stockCheck, wmsStorehouseStockList);
    }

    /**
     * 复盘
     * @author 梁建设
     * @since 2023/2/15 上午9:37
     */
    @Override
    @Transactional
    public int createReCheck(Long[] ids) {
        StockCheck stockCheck = new StockCheck();
        stockCheck.setIds(CollUtil.toList(ids));
        List<StockCheck> stockChecks = this.selectStockCheckList(stockCheck);
        for (StockCheck check : stockChecks) {
            if (CheckStatusEnum.COMPLETE.getCode().equals(check.getStatus())
                    ||CheckStatusEnum.CANCEL.getCode().equals(check.getStatus())
                    ||CheckStatusEnum.REVIEW_PASS.getCode().equals(check.getStatus())
                    ||CheckStatusEnum.REVIEW_FAILED.getCode().equals(check.getStatus())
            ){
                createRe(check);
            } else {
                throw new ServiceException("还未完成的盘点任务不能进行复盘，请先取消盘点");
            }
        }
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int cancelCheck(Long[] ids) {
        StockCheck stockCheck = new StockCheck();
        stockCheck.setIds(CollUtil.toList(ids));
        List<StockCheck> stockChecks = selectStockCheckList(stockCheck);
        if(CollUtil.isEmpty(stockChecks)){
            return 0;
        }
        for (StockCheck check : stockChecks) {
            if ((CheckStatusEnum.COMPLETE.getCode().equals(check.getStatus()))
                    || (CheckStatusEnum.REVIEW_CONFIRME.getCode().equals(check.getStatus()))
                    || (CheckStatusEnum.REVIEW_FAILED.getCode().equals(check.getStatus()))
                    || (CheckStatusEnum.REVIEW_PASS.getCode().equals(check.getStatus()))
            ) {
                throw new ServiceException("已完成的盘点任务不可以取消");
            } else {
                //解锁库存
                stockOccupyService.unLock(check);
            }
            //去除锁定
            stockOccupyService.unLock(check);
            check.setStatus(CheckStatusEnum.CANCEL.getCode());
        }
        this.batchUpdateStockCheck(stockChecks);
        for (StockCheck obj : stockChecks) {
            List<StockCheckDiff> diffs = stockCheckDiffService.selectStockCheckDiffListByCheckNo(obj.getNo());
            if (CollUtil.isEmpty(diffs)) {
                return 1;
            }
            Long[] diffIds = new Long[diffs.size()];
            for (int i = 0; i < diffs.size(); i++) {
                diffIds[i] = diffs.get(i).getId();
            }
            stockCheckDiffService.deleteStockCheckDiffByIds(diffIds);
        }
        return 1 ;

    }

    @Override
    public int submitReview(Long id) {
        StockCheck stockChecks = this.selectStockCheckById(id);
        if (stockChecks!=null){
            if (CheckStatusEnum.COMPLETE.getCode().equals(stockChecks.getStatus())){
                stockChecks.setStatus(CheckStatusEnum.REVIEW_CONFIRME.getCode());
            }else{
                throw new ServiceException("盘点状态为"+CheckStatusEnum.COMPLETE.getMessage()+"才能提交差异申请");
            }
        }
        this.updateStockCheck(stockChecks);
        return 1;
    }

    /**
     * 审核通过
     * @param vo
     * @return
     */
    @Override
    public int reviewPass(CheckReviewVo vo) {
        StockCheck check = this.selectStockCheckById(vo.getId());
        // TODO: 2023/8/9 需判断当前登录用户的角色，是仓库管理员才能操作
        if (check!=null){
            if (CheckStatusEnum.REVIEW_CONFIRME.getCode().equals(check.getStatus())){
                check.setStatus(CheckStatusEnum.REVIEW_PASS.getCode());
                check.setAuditSug(vo.getAuditSug());
                check.setCloseTime(new Date());
                List<StockCheckDiff> diffs = this.stockCheckDiffService.selectStockCheckDiffListByCheckNo(check.getNo());
                List<StockCheckDiff> inStockVos = diffs.stream().filter(e->e.getCheckQty()-e.getStockQty()>0).collect(Collectors.toList());
                List<StockCheckDiff> outStockVos = diffs.stream().filter(e->e.getStockQty()-e.getCheckQty()>0).collect(Collectors.toList());
                //添加其它入库单+流水+更新库存
                if (CollUtil.isNotEmpty(inStockVos)){
                    this.wmsInStockOrderService.directInStock(check.getNo(), InStockOrderTypeEnum.OTHER.getCode(), inStockVos,"盘盈入库"+check.getNo());
                }
                //添加其它出库单+流水+更新库存
                if (CollUtil.isNotEmpty(outStockVos)){
                    this.wmsOutStockOrderService.directOutStock(check.getNo(),OutStockOrderTypeEnum.OTHER.getCode(),outStockVos,"盘亏出库"+check.getNo());
                }
                //结束盘点，去除锁定
                stockOccupyService.unLock(check);
                this.updateStockCheck(check);
            }else{
                throw new ServiceException("盘点状态不是为"+CheckStatusEnum.REVIEW_CONFIRME.getMessage()+"不能进行差异审核");
            }
        }
        return 1;
    }

    /**
     * 审核不通过
     * @param vo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int reviewFail(CheckReviewVo vo) {
        StockCheck check = this.selectStockCheckById(vo.getId());
        if (check!=null){
            if (CheckStatusEnum.REVIEW_CONFIRME.getCode().equals(check.getStatus())){
                check.setStatus(CheckStatusEnum.REVIEW_FAILED.getCode());
                check.setAuditSug(vo.getAuditSug());
                check.setCloseTime(new Date());
                //自动创建复盘任务
                createRe(check);
                this.updateStockCheck(check);
            }else{
                throw new ServiceException("盘点状态不是为"+CheckStatusEnum.REVIEW_CONFIRME.getMessage()+"不能进行差异审核");
            }
        }
        return 1;
    }

    /**
     * 开始盘点
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int startCheck(Long[] ids) {
        StockCheck stockCheck = new StockCheck();
        stockCheck.setIds(CollUtil.toList(ids));
        List<StockCheck> stockChecks = this.selectStockCheckList(stockCheck);
        for (StockCheck check : stockChecks) {
            if (CheckStatusEnum.ALLOCATION.getCode().equals(check.getStatus())){
                check.setStatus(CheckStatusEnum.WAIT.getCode());
            }else{
                throw new ServiceException("请先分配盘点人员");
            }
        }
        this.batchUpdateStockCheck(stockChecks);
        createCheckTaskDetail(stockChecks);
        return 1;
    }

    private void createCheckTaskDetail(List<StockCheck> stockChecks) {
        if(CollUtil.isEmpty(stockChecks)){
            return;
        }
        for (StockCheck check : stockChecks) {
            List<StockCheckPlanDetail> planDetails;
            if (StringUtils.equals(check.getCheckWay(), CheckWayEnum.LOCATION.getCode())) {
                planDetails = stockCheckPlanDetailService.selectStockCheckPlanDetailByPlanNo(check.getPlanNo());
                createCheckDiffListByLocation(check.getNo(), planDetails);
            } else if (StringUtils.equals(check.getCheckWay(), CheckWayEnum.PRODUCT.getCode())) {
                planDetails = stockCheckPlanDetailService.selectStockCheckPlanDetailByPlanNo(check.getPlanNo());
                createCheckDiffListByLocationProduct(check.getNo(), planDetails);
            }
        }
    }

    private void createCheckDiffListByLocationProduct(String checkNo, List<StockCheckPlanDetail> planDetails) {
        if (CollUtil.isEmpty(planDetails)) {
            return;
        }
        List<StockCheckDiff> stockCheckDiffList = new ArrayList<>();
        for (StockCheckPlanDetail detail : planDetails) {
            WmsStorehouseStock stock = new WmsStorehouseStock();
            stock.setStorehouseNo(detail.getStorehouseNo());
            stock.setStorehouseAreaNo(detail.getAreaNo());
            stock.setProductNo(detail.getProductNo());
            List<WmsStorehouseStock> stockList = storehouseStockService.selectNewWmsStorehouseStockList(stock);
            if (CollUtil.isEmpty(stockList)) {
                continue;
            }
            for (WmsStorehouseStock storehouseStock : stockList) {
                StockCheckDiff stockCheckDiff = new StockCheckDiff();
                stockCheckDiff.setNo(TableNoUtil.getNo(StockCheckDiff.class));
                stockCheckDiff.setCheckNo(checkNo);
                stockCheckDiff.setCheckDetailNo(detail.getNo());
                stockCheckDiff.setProductNo(storehouseStock.getProductNo());
                stockCheckDiff.setProductName(storehouseStock.getProductName());
                stockCheckDiff.setProductUnit(storehouseStock.getCompany());
                stockCheckDiff.setStorehouseNo(storehouseStock.getStorehouseNo());
                stockCheckDiff.setAreaNo(storehouseStock.getStorehouseAreaNo());
                stockCheckDiff.setLocationNo(storehouseStock.getStorehouseLocationNo());
                stockCheckDiff.setStockQty(storehouseStock.getQty());
                stockCheckDiff.setCheckQty(null);
                stockCheckDiff.setContainerNo(storehouseStock.getContainerNo());
                stockCheckDiff.setTrayNo(storehouseStock.getTrayNo());
                stockCheckDiff.setBatchNo(storehouseStock.getBatchNo());
                stockCheckDiff.setStockStatus(CheckStatusEnum.CREATE.getCode());
                stockCheckDiffList.add(stockCheckDiff);
            }
        }
        stockCheckDiffService.batchInsertStockCheckDiff(stockCheckDiffList);
    }

    private void createCheckDiffListByLocation(String checkNo, List<StockCheckPlanDetail> planDetails) {
        if (CollUtil.isEmpty(planDetails)) {
            return;
        }
        List<StockCheckDiff> stockCheckDiffList = new ArrayList<>();
        for (StockCheckPlanDetail detail : planDetails) {
            WmsStorehouseStock stock = new WmsStorehouseStock();
            stock.setStorehouseNo(detail.getStorehouseNo());
            stock.setStorehouseAreaNo(detail.getAreaNo());
            stock.setStorehouseLocationNo(detail.getLocationNo());
            List<WmsStorehouseStock> stockList = storehouseStockService.selectNewWmsStorehouseStockList(stock);
            if (CollUtil.isEmpty(stockList)) {
                continue;
            }
            for (WmsStorehouseStock storehouseStock : stockList) {
                StockCheckDiff stockCheckDiff = new StockCheckDiff();
                stockCheckDiff.setNo(TableNoUtil.getNo(StockCheckDiff.class));
                stockCheckDiff.setCheckNo(checkNo);
                stockCheckDiff.setCheckDetailNo(detail.getNo());
                stockCheckDiff.setProductNo(storehouseStock.getProductNo());
                stockCheckDiff.setProductName(storehouseStock.getProductName());
                stockCheckDiff.setProductUnit(storehouseStock.getCompany());
                stockCheckDiff.setStorehouseNo(storehouseStock.getStorehouseNo());
                stockCheckDiff.setAreaNo(storehouseStock.getStorehouseAreaNo());
                stockCheckDiff.setLocationNo(storehouseStock.getStorehouseLocationNo());
                stockCheckDiff.setStockQty(storehouseStock.getQty());
                stockCheckDiff.setCheckQty(null);
                stockCheckDiff.setContainerNo(storehouseStock.getContainerNo());
                stockCheckDiff.setTrayNo(storehouseStock.getTrayNo());
                stockCheckDiff.setBatchNo(storehouseStock.getBatchNo());
                stockCheckDiff.setStockStatus(CheckStatusEnum.CREATE.getCode());
                stockCheckDiffList.add(stockCheckDiff);
            }
        }
        stockCheckDiffService.batchInsertStockCheckDiff(stockCheckDiffList);
    }

    @Transactional(rollbackFor = Exception.class)
    public void createRe(StockCheck check){
        StockCheck reCheck = new StockCheck();
        reCheck.setStorehouseNo(check.getStorehouseNo());
        reCheck.setStorehouseName(check.getStorehouseName());
        reCheck.setPlanNo(check.getPlanNo());
        reCheck.setPlanName(check.getPlanName());
        reCheck.setCheckType(check.getCheckType());
        reCheck.setCheckWay(check.getCheckWay());
        reCheck.setStatus(CheckStatusEnum.WAIT.getCode());
        reCheck.setChecker(check.getChecker());
        reCheck.setCheckerName(check.getCheckerName());
        reCheck.setIsRepeatCheck(YNEnum.Y.getCode());
        this.insertStockCheck(reCheck);
        List<StockCheckDetail> stockCheckDetails = this.stockCheckDetailService.selectStockCheckDetailByCheckNo(check.getNo());
        List<StockCheckDetail> reCheckDetails = new ArrayList<>();
        for (StockCheckDetail stockCheckDetail : stockCheckDetails) {
            StockCheckDetail reCheckDetail = new StockCheckDetail();
            reCheckDetail.setCheckNo(reCheck.getNo());
            reCheckDetail.setProductNo(stockCheckDetail.getProductNo());
            reCheckDetail.setProductName(stockCheckDetail.getProductName());
            reCheckDetail.setStorehouseNo(stockCheckDetail.getStorehouseNo());
            reCheckDetail.setAreaNo(stockCheckDetail.getAreaNo());
            reCheckDetail.setLocationNo(stockCheckDetail.getLocationNo());
            reCheckDetails.add(reCheckDetail);
        }
        //结束盘点，去除锁定
        stockOccupyService.unLock(check);
        //重新锁定库存
        stockCheckService.checkLock(reCheck,reCheckDetails);
        this.stockCheckDetailService.batchInsertStockCheckDetail(reCheckDetails);
        List<StockCheck> stockChecks = new ArrayList<>();
        stockChecks.add(reCheck);
        createCheckTaskDetail(stockChecks);
    }

    /**
     * 结束盘点任务时，需要复盘
     * @author 梁建设
     * @since 2023/3/6 下午2:54
     */
    @Override
    @Transactional
    public int createReCheckDirect(Long[] ids) {
        StockCheck stockCheck = new StockCheck();
        stockCheck.setIds(CollUtil.toList(ids));
        List<StockCheck> stockChecks = this.selectStockCheckList(stockCheck);
        for (StockCheck check : stockChecks) {
            if (CheckStatusEnum.COMPLETE.getCode().equals(check.getStatus())){
                createRe(check);
            } else {
                throw new ServiceException("该任务还未完成不能结束盘点");
            }
            check.setStatus(CheckStatusEnum.CLOSE.getCode());
        }
        this.batchUpdateStockCheck(stockChecks);
        return 1;
    }

    @Override
    @Transactional
    public int finish(Long[] ids) {
        StockCheck stockCheck = new StockCheck();
        stockCheck.setIds(CollUtil.toList(ids));
        List<StockCheck> stockChecks = this.selectStockCheckList(stockCheck);
        for (StockCheck check : stockChecks) {
            if (CheckStatusEnum.COMPLETE.getCode().equals(check.getStatus())){
                check.setStatus(CheckStatusEnum.CLOSE.getCode());
                check.setCloseTime(new Date());
                List<StockCheckDiff> diffs = this.stockCheckDiffService.selectStockCheckDiffListByCheckNo(check.getNo());
                List<StockCheckDiff> inStockVos = diffs.stream().filter(e->e.getCheckQty()-e.getStockQty()>0).collect(Collectors.toList());
                List<StockCheckDiff> outStockVos = diffs.stream().filter(e->e.getStockQty()-e.getCheckQty()>0).collect(Collectors.toList());
                //添加其它入库单+流水+更新库存
                if (CollUtil.isNotEmpty(inStockVos)){
                    this.wmsInStockOrderService.directInStock(check.getNo(), InStockOrderTypeEnum.OTHER.getCode(), inStockVos,"盘盈入库"+check.getNo());
                }
                //添加其它出库单+流水+更新库存
                if (CollUtil.isNotEmpty(outStockVos)){
                    this.wmsOutStockOrderService.directOutStock(check.getNo(),OutStockOrderTypeEnum.OTHER.getCode(),outStockVos,"盘亏出库"+check.getNo());
                }
                //结束盘点，去除锁定
                stockOccupyService.unLock(check);
            } else {
                throw new ServiceException("盘点任务状态不是已完成");
            }
        }
        this.batchUpdateStockCheck(stockChecks);
        return 1;
    }

    @Override
    public List<StockCheckPdaVo> listPda(StockCheckPdaVo stockCheck) {
        stockCheck.setChecker(SecurityUtils.getLoginUser().getUsername());
        List<StockCheck> stockChecks = stockCheckMapper.selectPdaStockCheckList(stockCheck);
        List<StockCheckPdaVo> checkPdaVoList = new ArrayList<>();
        stockChecks.stream().forEach(e->{
            List<StockCheckDetail> stockCheckDetails = stockCheckDetailService.selectStockCheckDetailByCheckNo(e.getNo());
            StockCheckPdaVo stockCheckPdaVo = BeanUtil.toBean(e, StockCheckPdaVo.class);
            String checkScope;
            if (CheckWayEnum.LOCATION.getCode().equals(e.getCheckWay())){
                checkScope = stockCheckDetails.stream().map(detail -> detail.getLocationNo()).collect(Collectors.joining(","));
            } else {
                checkScope = stockCheckDetails.stream().filter(detail->detail.getProductNo()!=null).map(detail -> detail.getProductNo()).collect(Collectors.joining(","));
            }
            stockCheckPdaVo.setCheckScope(checkScope);
            checkPdaVoList.add(stockCheckPdaVo);
        });
        return checkPdaVoList;
    }

    @Override
    public int allocation(StockCheck check) {
        StockCheck stockCheck = this.selectStockCheckById(check.getId());
        if (!(CheckStatusEnum.CREATE.getCode().equals(stockCheck.getStatus()) || CheckStatusEnum.ALLOCATION.getCode().equals(stockCheck.getStatus()))) {
            throw new ServiceException("任务状态不是" + CheckStatusEnum.CREATE.getMessage() + "或者" + CheckStatusEnum.ALLOCATION.getMessage());
        }
        stockCheck.setChecker(check.getChecker());
        stockCheck.setCheckerName(check.getCheckerName());
        stockCheck.setStatus(CheckStatusEnum.ALLOCATION.getCode());
        this.updateStockCheck(stockCheck);
        return 1;
    }

    @Override
    public CheckMainVo getDetail(Long id) {
        StockCheck stockCheck = this.selectStockCheckById(id);
        CheckMainVo checkMainVo = BeanUtil.toBean(stockCheck, CheckMainVo.class);
        List<StockCheckDetail> stockCheckDetails = this.stockCheckDetailService.selectStockCheckDetailByCheckNo(checkMainVo.getNo());
        List<CheckDetailVo> checkDetailVos = new ArrayList<>();
        for (StockCheckDetail stockCheckDetail : stockCheckDetails) {
            CheckDetailVo checkDetailVo = BeanUtil.toBean(stockCheckDetail, CheckDetailVo.class);
            List<StockCheckResult> stockCheckResults = this.stockCheckResultService.selectStockCheckResultByCheckDetailNo(checkDetailVo.getNo());
            checkDetailVo.setStockCheckResultList(stockCheckResults);
            checkDetailVos.add(checkDetailVo);
        }
        checkMainVo.setCheckDetailVos(checkDetailVos);
        return checkMainVo;
    }
}
